package com.jplus.core.utill.clazz;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jplus.core.utill.JUtil;

/**
 * 类操作工具类
 */
public class ClassUtil {

	private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);

	/**
	 * 获取类加载器
	 */
	public static ClassLoader getClassLoader() {
		return Thread.currentThread().getContextClassLoader();
	}

	/**
	 * 获取类路径
	 */
	public static String getClassPath() {
		String classpath = "";
		URL resource = getClassLoader().getResource("");
		if (resource != null) {
			classpath = resource.getPath();
		}
		return classpath;
	}

	/**
	 * 加载类（将自动初始化）
	 */
	public static Class<?> loadClass(String className) {
		return loadClass(className, true);
	}

	/**
	 * 加载类
	 */
	public static Class<?> loadClass(String className, boolean isInitialized) {
		if (JUtil.isEmpty(className))
			return null;
		Class<?> cls;
		try {
			logger.debug("\t>>{}", className);
			if (isInitialized)
				cls = Class.forName(className, isInitialized, getClassLoader());
			else
				cls = getClassLoader().loadClass(className);
		} catch (Exception e) {
			logger.error("Load class is error:" + className, e);
			throw new RuntimeException(e);
		}
		return cls;
	}

	public static boolean hasClass(String className) {
		try {
			loadClass(className, true);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 是否为 int 类型（包括 Integer 类型）
	 */
	public static boolean isInt(Class<?> type) {
		return type.equals(int.class) || type.equals(Integer.class);
	}

	/**
	 * 是否为 bool 类型（包括 Boolean 类型）
	 */
	public static boolean isBool(Class<?> type) {
		return type.equals(boolean.class) || type.equals(Boolean.class);
	}

	/**
	 * 是否为 long 类型（包括 Long 类型）
	 */
	public static boolean isLong(Class<?> type) {
		return type.equals(long.class) || type.equals(Long.class);
	}

	/**
	 * 是否为 double 类型（包括 Double 类型）
	 */
	public static boolean isDouble(Class<?> type) {
		return type.equals(double.class) || type.equals(Double.class);
	}

	/**
	 * 是否为 BigDecimal 类型
	 */
	public static boolean isDecimal(Class<?> type) {
		return type.equals(BigDecimal.class);
	}

	/**
	 * 是否为 String 类型
	 */
	public static boolean isString(Class<?> type) {
		return type.equals(String.class);
	}

	// ==============================================

	// * 扫描忽略注解
	private final static List<Class<?>> IGNORE = Arrays.asList(new Class<?>[] { Documented.class, Retention.class, Documented.class, Target.class });

	/**
	 * 查询目标类上是否有某注解，如果有，则返回该注解
	 */
	public static <T extends Annotation> List<T> findAnnotation(Class<?> res, Class<T> ans) {
		return findAnnotation(res, ans, 5);// 最多5级
	}

	public static <T extends Annotation> T findAnnotationOne(Class<?> res, Class<T> ans) {
		List<T> list = findAnnotation(res, ans, 5);// 最多5级
		return list.isEmpty() ? null : list.get(0);
	}

	public static <T extends Annotation> boolean hasAnnotation(Class<?> res, Class<T> ans) {
		return hasAnnotation(res, ans, 5);// 最多5级
	}

	/**
	 * 获取继承了某个注解的类上的第一个注解。 比如：
	 * 
	 * <pre>
	 * 已知类：
	 * &#64;Controller("index1")
	 * public class IndexAction {}
	 * 调用方法：
	 * findAnnotationParentOne(IndexAction.class,Component.class)
	 * 返回：@Controller("index1")
	 * </pre>
	 * 
	 */
	public static <T extends Annotation> Annotation findAnnotationParentOne(Class<?> res, Class<T> ans) {
		Annotation[] parentAns = res.getAnnotations();
		for (Annotation an : parentAns) {
			if (hasAnnotation(an.annotationType(), ans)) {
				return an;
			}
		}
		return null;
	}

	/**
	 * 查找类上的注解，有则返回该注解
	 */
	@SuppressWarnings("unchecked")
	public static <T extends Annotation> List<T> findAnnotation(Class<?> res, Class<T> ans, int depth) {
		List<T> list = new ArrayList<>();
		if (depth > 0) {
			Annotation[] as = res.getAnnotations();
			for (Annotation a : as) {
				Class<? extends Annotation> ra = a.annotationType();
				// 只要在忽略名单或 重复名单的，都不再去判断
				if (!(IGNORE.contains(ra))) {
					if (ra == ans) {
						list.add((T) a);
					} else {
						List<T> t = findAnnotation(ra, ans, depth - 1);
						if (t != null)
							list.addAll(t);
					}
				}
			}
		}
		return list;
	}

	/**
	 * 判断类上是否有某注解
	 */
	public static <T extends Annotation> boolean hasAnnotation(Class<?> res, Class<T> ans, int depth) {
		if (depth > 0) {
			if (res == ans)
				return true;
			Annotation[] as = res.getAnnotations();
			for (Annotation a : as) {
				Class<? extends Annotation> ra = a.annotationType();
				if (!(IGNORE.contains(ra))) {
					if (ra == ans) {
						return true;
					} else {
						boolean t = hasAnnotation(ra, ans, depth - 1);
						if (t)
							return t;
					}
				}
			}
		}
		return false;
	}
}
